<?php 
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.5.1 / SVN信息: $Id: class.StreamTasks.php 2166 2009-12-22 07:08:12Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/


namespace JCAT\PDRL\MultiTask ;


class StreamTasks implements ITask
{
    const READ = 1 ;
    const ERROR = 2 ;
    const WRITE = 4 ;
    
    const OUTPUT = 3 ; // READ | ERROR
    const INPUT = 4 ; // READ | ERROR
    
    
    /**
     * Description
     *
     * @access	public
     * @return	void
     */
    public function DoOnce(IDispatch $aDispatch)
    {
        $arrReadHandles = $this->arrReadHandles ;
        $arrWriteHandles = $this->arrWriteHandles ;
        $arrErrorHandles = $this->arrErrorHandles ;

        if( empty($arrReadHandles) and empty($arrWriteHandles) and empty($arrErrorHandles) )
        {
            return ;
        }

        $nReady = @stream_select($arrReadHandles,$arrWriteHandles,$arrErrorHandles,0,$this->nTimeoutMicroSec) ;
        if( !$nReady )
        {
            return ;
        }
        
        foreach ( array(
                self::READ => $arrReadHandles ,
                self::WRITE => $arrWriteHandles ,
                self::ERROR => $arrErrorHandles ) as $nType => $arrHandles )
        {
            foreach ($arrHandles as $hHandle)
            {
                if(!is_resource($hHandle))
                {
                    continue ;
                }
                
                $arrCallback = $this->QueryCallback($hHandle,$nType) ;
                $arrCallback['params'] = array_merge(
                        array($aDispatch,$this,$hHandle,$nType),
                        $arrCallback['params']
                ) ;
                
                call_user_func_array( $arrCallback['callback'], $arrCallback['params'] ) ;
            }
        }
        
    }


	/**
	 * Description
	 *
	 * @access	public
	 * @param	$hRead
	 * @param	$Callback
	 * @param	$arrParams=array()
	 * @return	bool
	 */
	public function AddReadHandle($hRead,$Callback,$arrParams=array())
	{
	    stream_set_blocking($hRead,0) ;
		return $this->AddHandle(self::READ,$hRead,$Callback,$arrParams) ;
	}
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$hWrite
	 * @param	$Callback
	 * @param	$arrParams=array()
	 * @return	bool
	 */
	public function AddWriteHandle($hWrite,$Callback,$arrParams=array())
	{
		return $this->AddHandle(self::WRITE,$hWrite,$Callback,$arrParams) ;
	}
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$hError
	 * @param	$Callback
	 * @param	$arrParams=array()
	 * @return	bool
	 */
	public function AddErrorHandle($hError,$Callback,$arrParams=array())
	{
		return $this->AddHandle(self::ERROR,$hError,$Callback,$arrParams) ;
	}
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$hRead
	 * @return	void
	 */
	public function RemoveReadHandle($hRead)
	{
	    $this->RemoveHandle(self::READ,$hRead) ;
	}
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$Parameter
	 * @return	void
	 */
	public function RemoveWriteHandle($hWrite)
	{
	    $this->RemoveHandle(self::WRITE,$hWrite) ;
	}
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$Parameter
	 * @return	void
	 */
	public function RemoveErrorHandle($hError)
	{
	    $this->RemoveHandle(self::ERROR,$hError) ;
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @param	$hHandle
	 * @return	array
	 */
	public function QueryCallback($hHandle,$nType)
	{
	    if( !isset(self::$arrTypesProps[$nType]) )
	    {
	        return null ;
	    }
	    
		$sKey = strval($hHandle) ;
	    $sType = self::$arrTypesProps[$nType] ;
	    $sPropName = "arr{$sType}s" ;
	    $arrCallbacks = &$this->$sPropName ;
	    
		return isset($arrCallbacks[$sKey])? $arrCallbacks[$sKey]: null ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	bool
	 */
	public function AddHandle($nType,$hHandle,$Callback,$arrParams=array())
	{
	    if( !is_resource($hHandle) or !isset(self::$arrTypesProps[$nType]) )
	    {
	        return false ;
	    }
	    $sType = self::$arrTypesProps[$nType] ;
	    
		$sKey = strval($hHandle) ;
		$sHandlePropName = "arr{$sType}Handles" ;
		$sCallbackPropName = "arr{$sType}s" ;
		$arrHandles = &$this->$sHandlePropName ;
		$arrCallbacks = &$this->$sCallbackPropName ;
		
		if( !isset($arrHandles[$sKey]) )
		{
			$arrHandles[$sKey] = $hHandle ;
			$arrCallbacks[$sKey] = array(
			        'callback' => $Callback ,
			        'params' => $arrParams ,
			) ;
		}
		
		return true ;
	}
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$Parameter
	 * @return	void
	 */
	public function RemoveHandle($nType,$hHandle)
	{
	    if( !isset(self::$arrTypesProps[$nType]) )
	    {
	        return null ;
	    }
	    $sType = self::$arrTypesProps[$nType] ;
	    
		$sKey = strval($hHandle) ;
		$sHandlePropName = "arr{$sType}Handles" ;
		$sCallbackPropName = "arr{$sType}s" ;
		$arrHandles = &$this->$sHandlePropName ;
		$arrCallbacks = &$this->$sCallbackPropName ;
		
		if(isset($arrHandles[$sKey]))
		{
			unset($arrHandles[$sKey]) ;
			unset($arrCallbacks[$sKey]) ;
		}
	}

	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrReadHandles = array() ;
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrWriteHandles = array() ;
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrErrorHandles = array() ;

	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrReads = array() ;
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrWrites = array() ;
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrErrors = array() ;
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrExceptQuits = array() ;
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nTimeoutMicroSec = 100 ;		// 0.0001 sec
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @static
	 * @var		array
	 */
	static private $arrTypesProps = array(
	        self::READ => 'Read' ,
	        self::WRITE => 'Write' ,
	        self::ERROR => 'Error' ,
	) ;
}
?>